/// -----------------------------------------------------------------------------------------------------------
/// Module      :  QueueStorageAdapterMetadataBrowseHandler.cs
/// Description :  This class is used while performing a connection-based browse for metadata from the target system.
/// -----------------------------------------------------------------------------------------------------------

#region Using Directives

using System;
using System.Collections.Generic;

using Microsoft.ServiceModel.Channels;
using Microsoft.ServiceModel.Channels.Common;

using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

#endregion

using BizTalkFactory.Adapters.AzureStorage.StorageAdapterConstants;

namespace BizTalkFactory.Adapters.AzureStorage
{
    internal class AzureStorageAdapterMetadataBrowseHandler : AzureStorageAdapterHandlerBase, IMetadataBrowseHandler
    {
        /// <summary>
        /// Initializes a new instance of the QueueStorageAdapterMetadataBrowseHandler class
        /// </summary>
        public AzureStorageAdapterMetadataBrowseHandler(AzureStorageAdapterConnection connection
            , MetadataLookup metadataLookup)
            : base(connection, metadataLookup)
        {
        }

        #region IMetadataBrowseHandler Members

        /// <summary>
        /// Retrieves an array of MetadataRetrievalNodes from the target system.
        /// The browse will return nodes starting from the childStartIndex in the path provided in absoluteName, and the number of nodes returned is limited by maxChildNodes.
        /// The method should complete within the specified timespan or throw a timeout exception.
        /// If absoluteName is null or an empty string, return nodes starting from the root + childStartIndex.
        /// If childStartIndex is zero, then return starting at the node indicated by absoluteName (or the root node if absoluteName is null or empty).
        /// </summary>
        public MetadataRetrievalNode[] Browse(string nodeId, int childStartIndex, int maxChildNodes, TimeSpan timeout)
        {
            List<MetadataRetrievalNode> nodes = new List<MetadataRetrievalNode>(new MetadataRetrievalNode[] { null });

            BrowseBlobStorageOperationsMetadata(nodeId, ref nodes);
            BrowseQueueStorageOperationsMetadata(nodeId, ref nodes);
            BrowseTableStorageOperationsMetadata(nodeId, ref nodes);

            return nodes.ToArray();
        }

        #endregion

        #region Queue Storage Implementation

        private void BrowseQueueStorageOperationsMetadata(string nodeId, ref List<MetadataRetrievalNode> nodes)
        {
            // Prevent displaying Queue operations when specifically instructed not to

            if (Connection.ConnectionFactory.Adapter.PollingStorage != StorageType.Unspecified &&
                Connection.ConnectionFactory.Adapter.PollingStorage != StorageType.Queue)
                return;

            // Queue Root Node

            if (MetadataRetrievalNode.Root.NodeId.Equals(nodeId))
            {
                MetadataRetrievalNode node = new MetadataRetrievalNode(MetadataNodeNames.QueueOp);
                node.DisplayName = MetadataNodeNames.QueueOp;
                node.IsOperation = false;
                node.Direction = MetadataRetrievalNodeDirections.Inbound | MetadataRetrievalNodeDirections.Outbound;

                nodes.Add(node);
            }

            // Queues

            else if (MetadataNodeNames.QueueOp.CompareTo(nodeId) == 0)
            {
                foreach (CloudQueue queue in Connection.QueueStorage.ListQueues())
                {
                    MetadataRetrievalNode node = new MetadataRetrievalNode(MetadataSearchBrowseNodeIds.QueueNodePrefix + queue.Name);
                    node.DisplayName = queue.Name;
                    node.Direction = MetadataRetrievalNodeDirections.Outbound | MetadataRetrievalNodeDirections.Inbound;
                    node.IsOperation = false;

                    nodes.Add(node);
                }
            }

            // Queue Operations

            else if (nodeId.StartsWith(MetadataSearchBrowseNodeIds.QueueNodePrefix))
            {
                string queueName = NodeIdHelper.ParseObjectNameFromOperationId(nodeId);
                CloudQueue queue = Connection.QueueStorage.GetQueueReference(queueName);

                nodes.Add(CreateOperationMetadataRetrievalNode(MetadataSearchBrowseNodeIds.QueueNodePrefix, queue.Name, OperationNames.GetMessage, MetadataRetrievalNodeDirections.Inbound));

                nodes.Add(CreateOperationMetadataRetrievalNode(MetadataSearchBrowseNodeIds.QueueNodePrefix, queue.Name, OperationNames.ClearMessages, MetadataRetrievalNodeDirections.Outbound));
                //nodes.Add(CreateOperationMetadataRetrievalNode(MetadataSearchBrowseNodeIds.QueueNodePrefix, queue.Name, OperationNames.DeleteMessage, MetadataRetrievalNodeDirections.Outbound));
                nodes.Add(CreateOperationMetadataRetrievalNode(MetadataSearchBrowseNodeIds.QueueNodePrefix, queue.Name, OperationNames.PutMessage, MetadataRetrievalNodeDirections.Outbound));
            }
        }

        #endregion

        #region Blob Storage Implementation

        private void BrowseBlobStorageOperationsMetadata(string nodeId, ref List<MetadataRetrievalNode> nodes)
        {
            System.Diagnostics.Debug.WriteLine("BlobOp : " + MetadataNodeNames.BlobOp);
            System.Diagnostics.Debug.WriteLine("nodeId : " + nodeId);
            System.Diagnostics.Debug.WriteLine("CompareTo : " + MetadataNodeNames.BlobOp.CompareTo(nodeId));

            // Prevent displaying Blob operations when specifically instructed not to

            if (Connection.ConnectionFactory.Adapter.PollingStorage != StorageType.Unspecified &&
                Connection.ConnectionFactory.Adapter.PollingStorage != StorageType.Blob)
                return;

            // Blob Root Node

            if (MetadataRetrievalNode.Root.NodeId.Equals(nodeId))
            {
                MetadataRetrievalNode node = new MetadataRetrievalNode(MetadataNodeNames.BlobOp);
                node.DisplayName = MetadataNodeNames.BlobOp;
                node.IsOperation = false;
                node.Direction = MetadataRetrievalNodeDirections.Inbound | MetadataRetrievalNodeDirections.Outbound;

                nodes.Add(node);
            }

            // Container

            else if (MetadataNodeNames.BlobOp.CompareTo(nodeId) == 0)
            {
                foreach (CloudBlobContainer container in Connection.BlobStorage.ListContainers())
                {
                    MetadataRetrievalNode node = new MetadataRetrievalNode(MetadataSearchBrowseNodeIds.BlobNodePrefix+container.Name);
                    node.DisplayName = container.Name;
                    node.Direction = MetadataRetrievalNodeDirections.Outbound | MetadataRetrievalNodeDirections.Inbound;
                    node.IsOperation = false;

                    nodes.Add(node);
                }
            }

            // blob Operations on container

            else
            {
                if (nodeId.StartsWith(MetadataSearchBrowseNodeIds.BlobNodePrefix))
                {

                    CloudBlobContainer container = Connection.BlobStorage.GetContainerReference(NodeIdHelper.ParseObjectNameFromOperationId(nodeId));

                    nodes.Add(CreateOperationMetadataRetrievalNode(MetadataSearchBrowseNodeIds.BlobNodePrefix, container.Name, OperationNames.GetBlob, MetadataRetrievalNodeDirections.Inbound));

                    nodes.Add(CreateOperationMetadataRetrievalNode(MetadataSearchBrowseNodeIds.BlobNodePrefix, container.Name, OperationNames.AddBlob, MetadataRetrievalNodeDirections.Outbound));
                    nodes.Add(CreateOperationMetadataRetrievalNode(MetadataSearchBrowseNodeIds.BlobNodePrefix, container.Name, OperationNames.DeleteBlob, MetadataRetrievalNodeDirections.Outbound));
                }
            }

        }

        #endregion

        private void BrowseTableStorageOperationsMetadata(string nodeId, ref List<MetadataRetrievalNode> nodes)
        {
            // Prevent displaying Table operations when specifically instructed not to

            if (Connection.ConnectionFactory.Adapter.PollingStorage != StorageType.Unspecified &&
                Connection.ConnectionFactory.Adapter.PollingStorage != StorageType.Table)
                return;

        }

        #region Implementation

        private MetadataRetrievalNode CreateOperationMetadataRetrievalNode(string prefix, string name, string operation, MetadataRetrievalNodeDirections direction)
        {
            MetadataRetrievalNode node =
                new MetadataRetrievalNode(
                    NodeIdHelper.CreateOperationId(prefix, name, operation));

            node.DisplayName = operation;
            node.Direction = direction;
            node.IsOperation = true;

            return node;
        }

        #endregion
    }
}
